package pl.edu.pw.ee.buildcity.services;

import org.fest.assertions.Fail;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import pl.edu.pw.ee.buildcity.dao.GenericDao;
import pl.edu.pw.ee.buildcity.entities.BuildDefinition;

import javax.annotation.Resource;
import javax.persistence.EntityNotFoundException;
import java.util.List;

import static org.fest.assertions.Assertions.assertThat;

/**
 * @author mgrzechocinski
 * @since 2009-11-22
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:domain-context.xml", "classpath:core-context.xml", "classpath:test-context.xml"})
public class GenericEntityServiceIntegrationTestCase {

	@Resource(name = "jpaGenericDao")
	private GenericDao<BuildDefinition, String> dao;

	@Resource(name = "buildDefinitionService")
	private GenericEntityService<BuildDefinition, String> buildDefinitionService;

	@After
	public void flushDB() {
		for (BuildDefinition buildDefinition : buildDefinitionService.getAll(BuildDefinition.class)) {
			buildDefinitionService.delete(buildDefinition);
		}
	}

	@Test
	public void shouldPersistEntity() {
		//Given
		BuildDefinition bdef1 = createBuildDefinition("buildDef1");

		//When
		buildDefinitionService.persist(bdef1);

		//Then
		assertThat(dao.getSingleResultOfQuery("from BuildDefinition")).isNotNull().isEqualTo(bdef1);
	}

	@Test
	public void shouldGetAllEntities() {
		//Given
		BuildDefinition bdef1 = createBuildDefinition("buildDef2");
		buildDefinitionService.persist(bdef1);
		BuildDefinition bdef2 = createBuildDefinition("buildDef3");
		buildDefinitionService.persist(bdef2);

		//When
		List<BuildDefinition> found = buildDefinitionService.getAll(BuildDefinition.class);

		//Then
		assertThat(found).isNotEmpty().hasSize(2).containsExactly(bdef1, bdef2);
	}

	@Test
	@Transactional
	public void shouldDeleteEntity() {
		//Given
		BuildDefinition bdef1 = createBuildDefinition("buildDef4");
		buildDefinitionService.persist(bdef1);

		//When
		buildDefinitionService.delete(bdef1);

		//Then
		try {
			dao.getSingleResultOfQuery("from BuildDefinition");
			Fail.fail("Should throw EntityNotFoundException while entity was removed from DB!");
		} catch (EntityNotFoundException e) {
			assertThat(e).isInstanceOf(EntityNotFoundException.class);
		}
	}

	@Test
	public void shouldMergeEntityInTwoTransactions() {
		//Given
		BuildDefinition bdef1 = createBuildDefinition("buildDef5");
		buildDefinitionService.persist(bdef1);

		assertThat(dao.getSingleResultOfQuery("from BuildDefinition").getNotifiedGG()).isNull();

		//When
		bdef1.setNotifiedGG("12345");
		buildDefinitionService.update(bdef1);

		//Then
		BuildDefinition merged = dao.getSingleResultOfQuery("from BuildDefinition");
		assertThat(merged).isNotNull();
		assertThat(merged.getNotifiedGG()).isEqualTo("12345");
	}

	public BuildDefinition createBuildDefinition(String name) {
		BuildDefinition bd = new BuildDefinition().withName(name);
		bd.setWorkingCopy(System.getProperty("user.dir"));
		bd.setRepositoryURL("http://example.com/trunk3");
		return bd;
	}
}
